#include    "flags.h"
#include    <iostream>

void Flags::Parse(int argc, char * argv[]) {
    for (int i = 1; i < argc; ++i) {
		if (argv[i] && argv[i][0]) {
			std::string param(argv[i]);
            std::string key;
            std::string val;

			size_t pos = param.find_first_of("=");
			size_t len = param.length();

            if (pos == std::string::npos) {
                key = param;
                val = "";
            } else if (pos == 0) {
                __Usage("Invalid command line arguments : " + param);
            } else if (pos == len - 1) {
                key = param.substr(0, len - 1);
                val = "";
            } else {
                key = param.substr(0, pos);
                val = param.substr(pos + 1, len - 1 - pos);
            }

            pos = key.find_first_not_of('-');
            if (pos == std::string::npos) {
                continue;
            }

            key = key.substr(pos);
            if (key == "h" || key == "help") {
                __Usage("");
            } else {
                auto it = _parser.find(key);
                if (it == _parser.end()) __Usage("Invalid command line arguments : " + param);
                it->second(val);
            }
		}
	}
}

void Flags::__Bind(const std::string & key, const std::string & format, const std::string & desc, Parser parser) {
    size_t pos = key.find_first_not_of('-');
    if (pos == std::string::npos) return;

    std::string final_key = key.substr(pos);
    std::string help = final_key + format;
    _usage[help] = desc;
    _order.push_back(help);

    auto it = _parser.find(final_key);
    if (it != _parser.end()) {
        __Usage("Flags::Bind error. Duplicated key : " + key);
    } else {
        _parser[final_key] = parser;
    }
}

void Flags::__Usage(const std::string & err) {
    std::cout << _title << "\n";
    if (!err.empty())
        std::cout << err << "\n" << std::endl;
    else
        std::cout << std::endl;

    size_t len = 0;
    for (auto & kv : _info)
        if (kv.first.size() > len) len = kv.first.size();
    for (auto & kv : _info) 
        std::cout << kv.first << std::string(len + 2 - kv.first.size(), ' ') << ": " << kv.second << std::endl;

    std::cout << "\n[USAGE]\n" << std::endl;

    len = 0;
    for (auto & k : _order)
        if (k.size() > len) len = k.size();

    for (auto & k : _order)
        std::cout << "\t" << k << std::string(len + 4 - k.size(), ' ') << _usage[k] << std::endl;

    exit(0);
}